var PKG_HEAD_BYTES = 4;

var MSG_FLAG_BYTES = 1;
var MSG_ROUTE_CODE_BYTES = 2;
var MSG_ID_MAX_BYTES = 5;
var MSG_ROUTE_LEN_BYTES = 1;

var MSG_ROUTE_CODE_MAX = 0xffff;

var MSG_COMPRESS_ROUTE_MASK = 0x1;
var MSG_TYPE_MASK = 0x7;

var copyArray = function(dest, doffset, src, soffset, length) {
    if ('function' === typeof src.copy) {
        // Buffer
        src.copy(dest, doffset, soffset, soffset + length);
    } else {
        // Uint8Array
        for (var index = 0; index < length; index++) {
            dest[doffset++] = src[soffset++];
        }
    }
};

var msgHasId = function(type) {
    return type === Message.TYPE_REQUEST || type === Message.TYPE_RESPONSE;
};

var msgHasRoute = function(type) {
    return type === Message.TYPE_REQUEST || type === Message.TYPE_NOTIFY || type === Message.TYPE_PUSH;
};

var caculateMsgIdBytes = function(id) {
    var len = 0;
    do {
        len += 1;
        id >>= 7;
    } while ( id > 0 );
    return len;
};

var encodeMsgFlag = function(type, compressRoute, buffer, offset) {
    if (type !== Message.TYPE_REQUEST && type !== Message.TYPE_NOTIFY && type !== Message.TYPE_RESPONSE && type !== Message.TYPE_PUSH) {
        throw new Error('unkonw message type: ' + type);
    }

    buffer[offset] = (type << 1) | (compressRoute ? 1 : 0);

    return offset + MSG_FLAG_BYTES;
};

var encodeMsgId = function(id, idBytes, buffer, offset) {
    var index = offset + idBytes - 1;
    buffer[index--] = id & 0x7f;
    while (index >= offset) {
        id >>= 7;
        buffer[index--] = id & 0x7f | 0x80;
    }
    return offset + idBytes;
};

var encodeMsgRoute = function(compressRoute, route, buffer, offset) {
    if (compressRoute) {
        if (route > MSG_ROUTE_CODE_MAX) {
            throw new Error('route number is overflow');
        }

        buffer[offset++] = (route >> 8) & 0xff;
        buffer[offset++] = route & 0xff;
    } else {
        if (route) {
            buffer[offset++] = route.length & 0xff;
            copyArray(buffer, offset, route, 0, route.length);
            offset += route.length;
        } else {
            buffer[offset++] = 0;
        }
    }

    return offset;
};

var encodeMsgBody = function(msg, buffer, offset) {
    copyArray(buffer, offset, msg, 0, msg.length);
    return offset + msg.length;
};

//var isSimpleType = function(type){
//    return ( type === 'uInt32' ||
//        type === 'sInt32' ||
//        type === 'int32'  ||
//        type === 'uInt64' ||
//        type === 'sInt64' ||
//        type === 'float'  ||
//        type === 'double' );
//};